{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Analysis of Interferometric Wavefront Data\n", "\n", "In this example, we will see how to use prysm to almost entirely supplant the software that comes with a commerical interferometer to analyze the wavefront of an optic. We begin by importing the relevant classes and setting some aesthetics for matplotlib." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from prysm import Interferogram, FringeZernike, sample_files, zernikefit\n", "\n", "from matplotlib import pyplot as plt\n", "plt.style.use('bmh')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We point prysm to the file, create a new interferogram, mask it to a circular region 100 mm across, subtract piston, tip/tilt and power, and evalute the PV and RMS wavefront error. We also plot the wavefront to make sure all has gone well" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "p = sample_files('dat') # sample Zygo .dat file, will be downloaded on demand and saved locally\n", "i = Interferogram.from_zygo_dat(p)\n", "i.crop().mask('circle', 40).crop()\n", "i.remove_piston_tiptilt_power()\n", "print(i.pv, i.rms)\n", "i.plot2d(clim=100, interp_method='bilinear') # +/- 100 nm\n", "plt.grid(False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The interferogram is cropped twice – once to enclose the valid data, then again to apply a mask centered on that region. For relatively conventional interferometry, you may want to stop here. If you want to use a different unit, that is easy enough," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i.change_phase_unit('waves')\n", "1/i.pv, 1/i.rms # print reciprocal -- \"one over xxx waves\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is no need to crop again since the outer bound has not changed. Perhaps you wish to evaluated the RMS within the 1 - 10 mm spatial periods," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i.change_phase_unit('nm')\n", "i.fill()\n", "i.bandlimited_rms(1,10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This value is derived from the PSD, so you must call fill first. Do not worry about the corners of the array containing data - it will be windowed out. If you do this on a part which has a central obscuration, the result will be incorrect. Otherwise, the value tends to agree to within +/- 5% of Zygo’s Mx ® software, though the authors of prysm do not believe they are calculated at all the same way.\n", "\n", "If you wish to decompose the wavefront into Zernike polynomials, that is easy enough." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# do this on data which has not been filled to avoid errors introduced by the fill value.\n", "coefficients = zernikefit(i.phase, terms=36, norm=True, map_='fringe')\n", "fz = FringeZernike(coefficients, dia=i.diameter, opd_unit=i.phase_unit, norm=True)\n", "fz" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This print might be a bit daunting, one may prefer to see the top few terms by magnitude," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fz.top_n(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or a barplot of all terms," ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fz.barplot_magnitudes(orientation='v', sort=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The sample data has a ciruclar clear aperture, but if it had a central obscuration (such as transmitted wavefront data for a telescope) that would be easy to mask too. PSD, and by extension bandlimited RMS values for data with annular support will be nonsensical." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i.mask('invertedcircle', 7)\n", "i.plot2d(clim=100) # +/- 100 nm\n", "plt.grid(False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.2" } }, "nbformat": 4, "nbformat_minor": 2 }